/**
 * 
 */
package t4j.concurrency;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

//土司，有个enum记录这个土司处于什么阶段
class Toast {
	public enum Status { DRY, BUTTERED, JAMMED	}//原始，黄油，果酱

	private Status status = Status.DRY;
	private final int id;

	public Toast(int idn) {
		id = idn;
	}

	// 涂黄油
	public void butter() {status = Status.BUTTERED;}

	// 涂果酱
	public void jam() {	status = Status.JAMMED;	}

	public Status getStatus() {	return status; }

	public int getId() { return id; }

	@Override
	public String toString() {
		return "Toast " + id + "： " + status;
	}
}

//土司队列类
class ToastQueue extends LinkedBlockingQueue<Toast> {}

//制作土司
class Toaster implements Runnable {
	private ToastQueue toastQueue;
	private int count = 0;
	private Random rand = new Random(47);

	public Toaster(ToastQueue tq) {
		toastQueue = tq;
	}

	@Override
	public void run() {
		try {
			while (!Thread.interrupted()) {
				TimeUnit.MILLISECONDS.sleep(100 + rand.nextInt(500));
				// Make toast
				Toast t = new Toast(count++);

				System.out.println(t);

				toastQueue.put(t);// toast put queue
			}
		} catch (InterruptedException e) {
			System.out.println("Toaster interrupted");
		}

		System.out.println("Toaster off");
	}
}

//涂黄油
class Butterer implements Runnable {
	private ToastQueue dryQueue, butteredQueue;

	public Butterer(ToastQueue dry, ToastQueue buttered) {
		dryQueue = dry;
		butteredQueue = buttered;
	}

	@Override
	public void run() {
		try {
			while (!Thread.interrupted()) {
				Toast t = dryQueue.take();// 从默认的土司队列里获取
				t.butter();// 涂黄油
				System.out.println(t);
				butteredQueue.put(t);// 加到已涂黄油的队列
			}
		} catch (InterruptedException e) {
			System.out.println("Butterer interrupted");
		}

		System.out.println("Butterer off");
	}
}

//涂果酱
class Jammer implements Runnable {
	private ToastQueue butteredQueue, finishedQueue;

	public Jammer(ToastQueue buttered, ToastQueue finished) {
		butteredQueue = buttered;
		finishedQueue = finished;
	}

	@Override
	public void run() {
		try {
			while (!Thread.interrupted()) {
				Toast t = butteredQueue.take();// 从已涂黄油的土司队列里获取;
				t.jam();// 涂果酱
				System.out.println(t);
				finishedQueue.put(t);// 加到完成的队列里
			}
		} catch (InterruptedException e) {
			System.out.println("Jammer interrupted");
		}

		System.out.println("Jammer off");

	}
}

// 吃客
class Eater implements Runnable {

	private ToastQueue finishedQueue;

	private int counter = 0;

	public Eater(ToastQueue finished) {
		finishedQueue = finished;
	}

	@Override
	public void run() {

		try {
			while (!Thread.interrupted()) {
				Toast t = finishedQueue.take();

				//检查土司ID是否和计算器一样和是否已涂果酱
				if (t.getId() != counter++ || t.getStatus() != Toast.Status.JAMMED) {
					System.out.println(">>>> Error: " + t);
					System.exit(1);

				} else {
					System.out.println("Chomp! " + t);// 吃土司
				}
			}
		} catch (InterruptedException e) {
			System.out.println("Eater interrupted");
		}

		System.out.println("Eater off");
	}

}

public class ToastOMatic {
	public static void main(String[] args) throws Exception {
		ToastQueue dryQueue = new ToastQueue(),butteredQueue = new ToastQueue(), finishedQueue = new ToastQueue();//创建三个队列
		
		ExecutorService exec = Executors.newCachedThreadPool();
		
		exec.execute(new Toaster(dryQueue));
		exec.execute(new Butterer(dryQueue, butteredQueue));
		exec.execute(new Jammer(butteredQueue, finishedQueue));
		exec.execute(new Eater(finishedQueue));
		
		TimeUnit.SECONDS.sleep(5);
		
		exec.shutdownNow();
		
		
	}
}
